﻿#include "canthread.h"
#include <QTime>
#include <QCoreApplication>
#include <QMetaType>
#include <string.h>
#include <vector>
#include <map>

CANThread::CANThread()
{
	stopped = false;
	//qRegisterMetaType<VCI_CAN_OBJ>("VCI_CAN_OBJ");
	//qRegisterMetaType<unsigned int>("DWORD");
}

void CANThread::stop()
{
	stopped = true;
}

//1.打开设备
bool CANThread::openDevice(UINT deviceType, UINT debicIndex, UINT baudRate0, UINT baudRate1)
{
	m_deviceType = deviceType;/* USBCAN-2A或USBCAN-2C或CANalyst-II */
	m_deviceIndex = debicIndex;/* 第1个设备 */
	m_baudRate0 = baudRate0;
	m_baudRate1 = baudRate1;

	unsigned int dwRel;
	dwRel = VCI_OpenDevice(m_deviceType, m_deviceIndex, 0);
	if (dwRel != 1) {
		qDebug() << "open channel 0 failed, " << dwRel;
		return false;
	}
	return true;
}

//2.初始化CAN
bool CANThread::initCAN()
{
	unsigned int dwRel = VCI_ClearBuffer(m_deviceType, m_deviceIndex, 0);
	dwRel = VCI_ClearBuffer(m_deviceType, m_deviceIndex, 1);
	VCI_INIT_CONFIG vic;
	vic.AccCode = 0x00000000;
	vic.AccMask = 0xFFFFFFFF;
	vic.Filter = 1;
	vic.Mode = 0;
	auto f = [](UINT baud, VCI_INIT_CONFIG& v) {
		switch (baud) {
		case 5:
			v.Timing0 = 0xFF;
			v.Timing1 = 0xBF;
		case 10:
			v.Timing0 = 0x31;
			v.Timing1 = 0x1c;
			break;
		case 20:
			v.Timing0 = 0x18;
			v.Timing1 = 0x1c;
			break;
		case 40:
			v.Timing0 = 0x87;
			v.Timing1 = 0xff;
			break;
		case 50:
			v.Timing0 = 0x09;
			v.Timing1 = 0x1c;
			break;
		case 80:
			v.Timing0 = 0x83;
			v.Timing1 = 0xff;
			break;
		case 100:
			v.Timing0 = 0x04;
			v.Timing1 = 0x1c;
			break;
		case 125:
			v.Timing0 = 0x03;
			v.Timing1 = 0x1c;
			break;
		case 200:
			v.Timing0 = 0x81;
			v.Timing1 = 0xfa;
			break;
		case 250:
			v.Timing0 = 0x01;
			v.Timing1 = 0x1c;
			break;
		case 400:
			v.Timing0 = 0x80;
			v.Timing1 = 0xfa;
			break;
		case 500:
			v.Timing0 = 0x00;
			v.Timing1 = 0x1c;
			break;
		case 666:
			v.Timing0 = 0x80;
			v.Timing1 = 0xb6;
			break;
		case 800:
			v.Timing0 = 0x00;
			v.Timing1 = 0x16;
			break;
		case 1000:
			v.Timing0 = 0x00;
			v.Timing1 = 0x14;
			break;
		case 33:
			v.Timing0 = 0x09;
			v.Timing1 = 0x6f;
			break;
		case 66:
			v.Timing0 = 0x04;
			v.Timing1 = 0x6f;
			break;
		case 83:
			v.Timing0 = 0x03;
			v.Timing1 = 0x6f;
			break;
		default:
			break;
		}
		};
	f(m_baudRate0, vic);
	dwRel = VCI_InitCAN(m_deviceType, m_deviceIndex, 0, &vic);
	if (dwRel != 1) {
		qDebug() << "init can 0, failed, " << dwRel;
		return false;
	}

	f(m_baudRate1, vic);
	dwRel = VCI_InitCAN(m_deviceType, m_deviceIndex, 1, &vic);
	if (dwRel != 1) {
		qDebug() << "init can 1, failed, " << dwRel;
		return false;
	}
	else
		qDebug() << "init success";

	//VCI_BOARD_INFO vbi;
	//dwRel = VCI_ReadBoardInfo(m_deviceType, m_deviceIndex, &vbi);
	//if (dwRel != 1)
	//	return false;
	//else
	//	emit boardInfo(vbi);
	return true;
}

//3.启动CAN
bool CANThread::startCAN()
{
	if (VCI_StartCAN(m_deviceType, m_deviceIndex, 0) != 1)
	{
		qDebug() << "start 0 fail.";
		return false;
	}
	else
		qDebug() << "start 0 success.";
	if (VCI_StartCAN(m_deviceType, m_deviceIndex, 1) != 1)
	{
		qDebug() << "start 1 fail.";
		return false;
	}
	else
		qDebug() << "start 1 success.";
	return true;
}

//4.发送数据
bool CANThread::sendData(UINT channel, UINT ID, BYTE remoteFlag, BYTE externFlag, const unsigned char* data, size_t len)
{
	unsigned int dwRel;
	VCI_CAN_OBJ vco;
	vco.ID = ID;
	vco.RemoteFlag = remoteFlag;
	vco.ExternFlag = externFlag;
	vco.DataLen = len;
	for (UINT j = 0; j < len; j++)
		vco.Data[j] = data[j];
	dwRel = VCI_Transmit(m_deviceType, m_deviceIndex, channel, &vco, 1);
	if (dwRel > 0)
		return true;
	else
		return false;
}

bool CANThread::sendData(UINT channel, UINT ID, const unsigned char* data, size_t len)
{
	assert(len <= 8);
	unsigned int dwRel;
	VCI_CAN_OBJ vco;
	memset(&vco, 0, sizeof(vco));
	vco.ID = ID;
	int frameCount = len / 8 + (len % 8 == 0 ? 0 : 1);
	std::vector<VCI_CAN_OBJ> objs;
	objs.reserve(frameCount);

	for (int i = 0; i < frameCount; ++i) {
		vco.DataLen = (i == frameCount - 1 ? len % 8 : 8);
		vco.DataLen = (vco.DataLen == 0?8:vco.DataLen);
		memcpy(vco.Data, data + i * 8, vco.DataLen);
		objs.push_back(vco);
	}
	//for (UINT j = 0; j < len; j++)
		//vco.Data[j] = data[j];
	dwRel = VCI_Transmit(m_deviceType, m_deviceIndex, channel, objs.data(), objs.size());
	for (auto& obj : objs) {
		//qDebug() << "send:" << dwRel << ' ' << obj.ID << ',' << (int)obj.Data[0] << ',' << (int)obj.Data[1] << ',' << (int)obj.Data[2] << ',' << (int)obj.Data[3] << ',' << (int)obj.Data[4] << ',' << (int)obj.Data[5] << ',' << (int)obj.Data[6] << ',' << (int)obj.Data[7];
	}
	if (dwRel == -1) {
		// disconnected
	}
	if (dwRel == objs.size())
		return true;
	return false;
}

int CANThread::recvData(UINT channel, QQueue<CanData>& data) {
	int num = VCI_GetReceiveNum(m_deviceType, m_deviceIndex, channel);
	if (num < 0) {
		qDebug()<<"recv neg:" << num;
		return -1;
	}
	//qDebug()<<"recv:" << num;
	std::vector<VCI_CAN_OBJ> vco(num);
	num = VCI_Receive(m_deviceType, m_deviceIndex, channel, vco.data(), num, 0);
	if (num < 0) {
		qDebug()<<"recv neg2:" << num;
		return -2;
	}
	if (num > 0) {
		//qDebug() << "recv2:" << num;
	}
	for (DWORD i = 0; i < num; ++i) {
		CanData canData;
		canData.id = vco[i].ID;
		memset(canData.data, 0, CANDATASIZE);
		memcpy(canData.data, vco[i].Data, vco[i].DataLen);
		data.enqueue(std::move(canData));
	}

	return num;
}

int CANThread::recvData(UINT channel, QVector<CanData>& data) {
	DWORD num = VCI_GetReceiveNum(m_deviceType, m_deviceIndex, channel);
	if (num == -1) {
		return -1;
	}
	std::vector<VCI_CAN_OBJ> vco(num);
	num = VCI_Receive(m_deviceType, m_deviceIndex, channel, vco.data(), num, 0);
	if (num == -1) {
		return -2;
	}
	for (DWORD i = 0; i < num; ++i) {
		CanData canData;
		canData.id = vco[i].ID;
		memset(canData.data, 0, CANDATASIZE);
		memcpy(canData.data, vco[i].Data, vco[i].DataLen);
		data.push_back(std::move(canData));
	}
	return num;
}

//5.关闭设备
void CANThread::closeDevice()
{
	VCI_CloseDevice(m_deviceType, m_deviceIndex);
}

//0.复位设备，  复位后回到3
bool CANThread::reSetCAN()
{
	if (VCI_ResetCAN(m_deviceType, m_deviceIndex, 0) != 1)
	{
		qDebug() << "reset 0 fail.";
		return false;
	}
	else
		qDebug() << "reset 0 success.";
	if (VCI_ResetCAN(m_deviceType, m_deviceIndex, 1) != 1)
	{
		qDebug() << "reset 1 fail.";
		return false;
	}
	else
		qDebug() << "reset 1 success.";
	return true;
}

void CANThread::run()
{
	//while (!stopped)
	//{
	//	unsigned int dwRel;
	//	VCI_CAN_OBJ vco[2500];
	//	dwRel = VCI_Receive(m_deviceType, m_deviceIndex, 0, vco, 2500, 0);
	//	if (dwRel > 0)
	//		emit getProtocolData(vco, dwRel, 0);
	//	dwRel = VCI_Receive(m_deviceType, m_deviceIndex, 1, vco, 2500, 0);
	//	if (dwRel > 0)
	//		emit getProtocolData(vco, dwRel, 1);
	//	sleep(30);
	//}
	//stopped = false;
}

void CANThread::sleep(int msec)
{
	QTime dieTime = QTime::currentTime().addMSecs(msec);
	while (QTime::currentTime() < dieTime)
		QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
